package com.cskaoyan.javase.oop3._0abstract._1basic;

/**
 * @description: 抽象类的成员, 子类以及自身特点
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

import java.time.Period;

/**
 * 抽象类的定义:
 *      [访问权限修饰符] abstract class 类名{
 *      }
 * 注意事项:
 *      1,类名,作为抽象类的类名,很多时候存在一种特殊命名规则(不是强制的)
 *          会使用"Abstract" + 类名的形式,表示这是一个抽象类
 *          比如AbstractPerson、AbstractAnimal
 *      2,类定义的时候,能够使用的修饰符不多,final和abstract是少有的两个
 *          他两个是矛盾的,不能共存的
 *          final是禁止继承的类,而abstract是专门为了继承而定义的抽象类
 *
 *  抽象类的成员特点:
 *      1,成员变量
 *          抽象类的成员变量和普通类是一致的,普通类中能够定义的成员变量抽象类也可以
 *
 *      2,成员方法
 *          a,普通成员方法:抽象类中是可以定义普通成员方法的
 *          为什么?有什么用?
 *          虽然抽象类不能创建对象,但是可以有子类,所以普通成员方法虽然自己不能用,但是可以让子类继承使用
 *          如果在多个子类中有一个方法都需要去实现,可以提取到抽象父类中,这样:
 *              子类要么直接作为默认实现去使用,要么自己重写,选择权在子类手里
 *
 *          b,静态成员方法:抽象类中是可以定义静态成员方法的
 *           抽象类中静态方法也可以类名点去调用它,当然也可以使用子类类名点
 *           实际开发中,静态成员方法很少在抽象类去写
 *
 *          以上总结:  普通类中能够定义的方法在抽象类中都是可以定义的
 *          抽象类中可以没有抽象方法吗?
 *              是可以的,但是这并没有什么意义,抽象类的诞生就是为了写抽象方法
 *              有些程序员会把一个类定义成抽象类,目的是为了让该类不能创建对象,这显然是不合适的
 *              如果有不创建对象的需求,还是私有化构造方法把
 *
 *          c,抽象方法
 *          语法:
 *               [权限修饰符] abstract 返回值类型 方法名(形参列表);
 *          唯一需要注意的是,不要忘记分号";"
 *          抽象方法最重要的特点是: 继承了抽象类的抽象方法,必须实现它,除非这个类是抽象类
 *          抽象方法的这个作用,称之为"占位"的作用,一旦抽象类中写了一个抽象方法,就意味着普通子类一定要实现
 *
 *      以上总结: 从成员变量和成员方法的角度来说,抽象类只比普通类多了一个抽象方法,其余的是一致的
 *
 *      3,构造器
 *          抽象类不能创建对象,那么它有构造器?
 *          有,自己虽然不能用,但是可以给子类用(子类对象初始化时,需要调用父类构造器给父类成员赋值)
 *
 *          立刻我说一句话:
 *              1,在java当中任何一个类,都有构造器
 *                  类分为普通类和抽象类,它们都有构造器,即便没有显式给出,也隐式给出了默认无参
 *              2,任何一个独立定义的普通类,直接加上一个abstract声明变为抽象类,不会报错
 *                  因为普通类有的,我抽象类也有
 *
 *      4,代码块
 *          1,静态代码块: 有
 *          2,构造代码块: 有(因为它随着构造器执行)
 *
 *
 * 抽象类的子类的特点：
 *      1,普通类: 必须实现抽象类中的所有抽象方法
 *      2,抽象类: 无需实现抽象方法,或者自由实现几个
 *
 *
 * 抽象类当中的抽象方法需要使用abstract关键字声明
 *  思考一下,以下方法能不能声明抽象?
 *      1,静态方法: 不能被重写的方法,抽象方法定义出来就是为了被重写(渴望被重写),所以这显然是不行
 *
 *      2,构造方法: 根本就不能被继承,更不谈重写
 *
 *      3,final方法: final方法不能被重写,所以也不能抽象
 *      4,private方法: 没有权限不能重写,所以也不能和abstract共用.为了鼓励重写抽象方法,抽象方法的访问权限往往是public
 *
 */
public class Demo {
    public static void main(String[] args) {
        /*AbstractPerson.testStatic();
        Student.testStatic();*/

        Student s = new Student(10, 20, 30);
        System.out.println(s.a); //10
        System.out.println(s.b); //20
        System.out.println(s.age); //30
    }
}

abstract class AbstractPerson {
    static {
    }

    {

    }

    //定义成员变量
    int a;
    int b = 20;
    static int c = 30;
    static final int D = 40;

    //定义普通成员方法
    public void test() {
        System.out.println("我是普通成员方法");
    }

    //定义静态成员方法
    //Illegal combination of modifiers: 'abstract' and 'static'
    public static void testStatic() {
        System.out.println("我是静态成员方法");
    }

    //定义抽象方法
    public abstract void testAbstract();

    public abstract void testAbstract2();

    public AbstractPerson(int a, int b) {
        this.a = a;
        this.b = b;
    }

    public AbstractPerson() {
    }
}

//Class 'Student' must either be declared abstract or implement abstract method 'testAbstract()' in 'AbstractPerson'
class Student extends AbstractPerson {
    int age;

    public Student(int a, int b, int age) {
        super(a, b);
        this.age = age;
    }

    public Student() {
    }

    //重写testAbstract()方法

    /**
     * 重写的方式:
     *  1,alt+insert
     *  2,写父类的方法名
     *  3,直接报错处alt+回车
     *
     */
    @Override
    public void testAbstract() {
        System.out.println("Student类重写父类抽象方法testAbstract");
    }

    @Override
    public void testAbstract2() {
        System.out.println("Student类重写父类抽象方法testAbstract2");

    }

}

abstract class Teacher extends AbstractPerson {

    //抽象子类中,也可以去写抽象方法的实现,但是这个实现不是强制的,可以自由选择

}